use crate::dto::{
    dept::DeptTree,
    match_no_res_ok, match_ok, menu, res_json_custom, res_json_err, res_json_ok,
    user::{
        CaptchaRes, LoginReq, LoginRes, SysAuthPayload, SysUpdateUserPwdPayload, SysUserAuthRole,
        SysUserChangeStatusPayload, SysUserDetail, SysUserEditPayload, SysUserEditPwdPayload,
        SysUserList, SysUserListPayload, SysUserModifyPayload, SysUserProfile, UserInfo,
    },
    Page, Res, ResObj,
};
use crate::service::{dept_service, menu_service, role_service, user_service};
use crate::utils::{captcha, md5::create_md5, redis, webtoken::create_token};
use hypers::prelude::*;
use uuid::Uuid;

pub struct User;

#[openapi(prefix = "/system", name = "/user", tag = "用户")]
impl User {
    /// 部门树
    #[get(
        "/deptTree", 
        tag("部门"), 
        response((status = 200,body=ResObj<Vec<DeptTree>>,description ="部门树"))
    )]
    async fn get_dept_tree() -> Res<Vec<DeptTree>> {
        match_ok(dept_service::get_dept_tree().await)
    }

    /// 用户列表
    #[get(
        "/list", 
        tag("部门"), 
        parameter(
            SysUserListPayload
        ),
        response((status = 200,body=ResObj<Vec<SysUserList>>,description ="用户列表"))
    )]
    async fn get_user_page(payload: SysUserListPayload) -> Res<Page<SysUserList>> {
        match_ok(
            user_service::get_user_page(
                payload.page_num,
                payload.page_size,
                payload.user_name.clone(),
                payload.phone_number.clone(),
                payload.status.clone(),
                payload.begin_time,
                payload.end_time,
                payload.dept_id,
            )
            .await,
        )
    }

    /// 个人中心-修改密码
    #[put(
        "/profile/updatePwd",
        response(
            (status = 200,body=ResObj<()>,description = "个人中心-修改用户密码")
        )
    )]
    async fn reset_user_password(
        payload: Json<SysUpdateUserPwdPayload>,
        req: &mut Request,
    ) -> Res<()> {
        let user_id: i32 = req.get::<i32>("userId").expect("获取用户信息错误");
        if let (Some(old_password), Some(new_password)) =
            (&payload.old_password, &payload.new_password)
        {
            if old_password.len() > 0 && new_password.len() > 0 {
                return match_no_res_ok(
                    user_service::reset_user_password(
                        user_id,
                        old_password.clone().to_string(),
                        new_password.clone().to_string(),
                    )
                    .await,
                );
            } else {
                return Err(res_json_custom(400, "旧密码和新密码不能为空".to_string()));
            }
        } else {
            Err(res_json_custom(400, "旧密码和新密码不能为空".to_string()))
        }
    }

    /// 个人中心-获取用户信息
    #[get(
        "/profile"
        response(
            (status = 200,body=ResObj<SysUserProfile>,description = "个人中心-获取用户信息")
        )
    )]
    async fn get_user_profile(req: &mut Request) -> Res<SysUserProfile> {
        let user_id: i32 = req.get::<i32>("userId").expect("获取用户信息错误");
        match_ok(user_service::get_user_profile_service(user_id).await)
    }

    /// 用户详情
    #[get(
        "/:id"
        response(
            (status = 200,body=ResObj<SysUserDetail>,description ="用户详情")
        ),
    )]
    async fn get_user_detail(id: Path<Option<i64>>) -> Res<SysUserDetail> {
        match_ok(user_service::get_detail_by_id(id.0).await)
    }

    /// 删除用户
    #[delete(
        "/:id"
        response(
            (status = 200,body=ResObj<()>,description ="删除用户")
        ),
    )]
    async fn del_user(id: Path<i64>) -> Res<()> {
        match_no_res_ok(user_service::del_user(id.0).await)
    }

    /// 获取部门和角色列表
    #[get(
        "/",
        response(
            (status = 200,body=ResObj<SysUserDetail>,description ="获取部门和角色列表")
        ),
    )]
    async fn get_dept_and_role() -> Res<SysUserDetail> {
        match_ok(user_service::get_detail_by_id(None).await)
    }

    /// 修改用户状态
    #[put(
        "/changeStatus",
        response(
            (status = 200,body=ResObj<()>,description ="修改用户状态")
        ),
    )]
    async fn put_change_status_by_id(payload: Json<SysUserChangeStatusPayload>) -> Res<()> {
        match_no_res_ok(
            user_service::update_user_status_by_id(payload.status.clone(), payload.user_id).await,
        )
    }

    /// 添加用户
    #[post(
        "/",
        response(
            (status = 200,body=ResObj<()>,description ="添加用户")
        ),
    )]
    async fn post_add_user(payload: Json<SysUserModifyPayload>, req: &mut Request) -> Res<()> {
        let user_id = req.get::<i32>("userId").unwrap();
        let mut password = payload.password.clone();
        password.push_str("salvo_admin");
        match_no_res_ok(
            user_service::add_user(
                user_id,
                payload.dept_id,
                payload.email.clone(),
                payload.nick_name.clone(),
                payload.user_name.clone(),
                create_md5(password),
                payload.status.clone(),
                payload.sex.clone(),
                payload.phone_number.clone(),
                payload.post_ids.clone(),
                payload.role_ids.clone(),
                payload.remark.clone(),
            )
            .await,
        )
    }

    /// 修改用户
    #[put(
        "/",
        response(
            (status = 200,body=ResObj<()>,description ="修改用户")
        ),
    )]
    async fn put_edit_user(payload: Json<SysUserEditPayload>, req: &mut Request) -> Res<()> {
        let user_id = req.get::<i32>("userId").unwrap();
        match_no_res_ok(
            user_service::edit_user(
                user_id,
                payload.user_id,
                payload.dept_id,
                payload.email.clone(),
                payload.nick_name.clone(),
                payload.status.clone(),
                payload.sex.clone(),
                payload.phone_number.clone(),
                payload.post_ids.clone(),
                payload.role_ids.clone(),
                payload.remark.clone(),
            )
            .await,
        )
    }

    /// 修改用户密码
    #[put(
        "resetPwd",
        response(
            (status = 200,body=ResObj<()>,description ="修改用户密码")
        ),
    )]
    async fn update_user_pwd(payload: Json<SysUserEditPwdPayload>) -> Res<()> {
        match_no_res_ok(
            user_service::update_user_pwd(payload.user_id, create_md5(payload.password.clone()))
                .await,
        )
    }

    /// 查询用户详情和角色列表
    #[get(
        "authRole/:id",
        response(
            (status = 200,body=ResObj<SysUserAuthRole>,description ="查询用户详情和角色列表")
        ),
    )]
    async fn get_user_auth_role_by_id(id: Path<i64>) -> Res<SysUserAuthRole> {
        match_ok(user_service::get_user_auth_role_by_id(id.0).await)
    }

    /// 修改用户权限
    #[put(
        "authRole",
        parameter(
            SysAuthPayload
        ),
        response(
            (status = 200,body=ResObj<()>,description ="修改用户权限")
        ),
    )]
    async fn add_user_and_role(user_role: SysAuthPayload) -> Res<()> {
        match user_role.role_ids {
            Some(v) => {
                let role_ids_str: Vec<&str> = v.split(",").collect::<Vec<&str>>();
                let role_ids = role_ids_str
                    .into_iter()
                    .map(|it| it.parse::<i64>().unwrap())
                    .collect::<Vec<i64>>();
                match_no_res_ok(
                    user_service::add_user_and_role(user_role.user_id, Some(role_ids)).await,
                )
            }
            None => match_no_res_ok(user_service::add_user_and_role(user_role.user_id, None).await),
        }
    }

    /// 退出登录
    #[post(
        "logout",
        response(
            (status = 200,body=ResObj<()>,description ="退出登录")
        ),
    )]
    async fn log_out(req: &mut Request) -> Res<()> {
        if let Some(token) = req.headers().get("Authorization") {
            match redis::del(
                token
                    .to_str()
                    .map_or("", |v| v)
                    .to_string()
                    .replace("Bearer ", ""),
            ) {
                _ => Ok(res_json_ok(None)),
            }
        } else {
            Ok(res_json_custom(401, "用户无权限".to_owned()))
        }
    }
}

pub struct Base;

#[openapi]
impl Base {
    /// 获取用户信息
    #[get(
        "getInfo",
        response(
            (status = 200,body=ResObj<UserInfo>,description ="获取用户信息")
        ),
    )]
    async fn get_info(req: &mut Request) -> Res<UserInfo> {
        let user_id = req.get::<i32>("userId").unwrap();
        match user_service::get_user_by_id(user_id).await {
            Ok(user_op) => {
                if let Some(user) = user_op {
                    match role_service::get_roles_by_user_id(user_id).await {
                        Ok(role_list) => {
                            if role_list.contains(&String::from("admin")) {
                                let user_info = UserInfo {
                                    user,
                                    roles: vec![String::from("admin")],
                                    permissions: vec!["*:*:*".to_string()],
                                };
                                Ok(res_json_ok(Some(user_info)))
                            } else {
                                let permissions =
                                    menu_service::get_menu_by_role_id(true, role_list.join(","))
                                        .await
                                        .unwrap();
                                let user_info = UserInfo {
                                    user,
                                    roles: role_list,
                                    permissions,
                                };
                                Ok(res_json_ok(Some(user_info)))
                            }
                        }
                        Err(err) => Err(res_json_custom(400, err.to_string())),
                    }
                } else {
                    Err(res_json_custom(400, "用户不存在".to_string()))
                }
            }
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }
    /// 获取用户路由
    #[get(
        "getRouters",
        response(
            (status = 200,body=ResObj<Vec<menu::Router>>,description ="获取用户路由")
        ),
    )]
    async fn get_routers(req: &mut Request) -> Res<Vec<menu::Router>> {
        let user_id = req.get::<i32>("userId").unwrap();
        // Ok(res_json_ok(Some(user_id)))
        match role_service::get_roles_by_user_id(user_id).await {
            Ok(role_list) => {
                if role_list.contains(&String::from("admin")) {
                    menu_service::get_router_tree(true, user_id)
                        .await
                        .map_or_else(
                            |err| Err(res_json_custom(400, err.to_string())),
                            |v| Ok(res_json_ok(Some(v))),
                        )
                } else {
                    menu_service::get_router_tree(false, user_id)
                        .await
                        .map_or_else(
                            |err| Err(res_json_custom(400, err.to_string())),
                            |v| Ok(res_json_ok(Some(v))),
                        )
                }
            }
            Err(err) => Err(res_json_custom(400, err.to_string())),
        }
    }

    /// 获取验证码
    #[get(
        "captchaImage",
        response(
            (status = 200,body=ResObj<CaptchaRes>,description ="获取验证码")
        ),
    )]
    async fn get_captcha() -> Res<CaptchaRes> {
        if let (captcha_str, Some(base64)) = captcha::create_captcha() {
            let uuid = Uuid::new_v4().to_string();
            // 验证码转小写
            redis::set_ex(&uuid, captcha_str.to_lowercase(), 300).unwrap();
            Ok(res_json_ok(Some(CaptchaRes {
                img: base64,
                captcha_enabled: Some(true),
                uuid,
            })))
        } else {
            Err(res_json_err("验证码生成失败".to_owned()))
        }
    }

    /// 登录
    #[post(
        "login",
        response(
            (status = 200,body=ResObj<LoginRes>,description ="登录")
        ),
    )]
    async fn login(login_body: Json<LoginReq>) -> Res<LoginRes> {
        if let Some(captcha_str) = login_body.code.clone() {
            let captcha: String = redis::get(login_body.uuid.clone()).map_or(String::new(), |v| v);
            if captcha.is_empty() || !captcha_str.eq(&captcha) {
                Err(res_json_err("验证码错误".to_owned()))
            } else {
                redis::del(login_body.uuid.clone()).unwrap();
                if let (Some(username), Some(mut password)) =
                    (login_body.username.clone(), login_body.password.clone())
                {
                    password.push_str("salvo_admin");
                    match user_service::get_user_by_up(username, create_md5(password)).await {
                        Ok(r_op) => {
                            if let Some(user) = r_op {
                                match create_token(user.user_id.try_into().unwrap(), user.user_name)
                                {
                                    Ok(token) => {
                                        redis::set_ex(&token, user.user_id, 3600).unwrap();
                                        Ok(res_json_ok(Some(LoginRes { token })))
                                    }
                                    Err(_err) => {
                                        Err(res_json_custom(400, "token生成失败".to_owned()))
                                    }
                                }
                            } else {
                                Err(res_json_custom(400, "用户不存在".to_owned()))
                            }
                        }
                        Err(err) => Err(res_json_err(err.to_string())),
                    }
                } else {
                    Err(res_json_custom(400, "用户账号或密码必须填写".to_owned()))
                }
            }
        } else {
            Err(res_json_err("验证码错误".to_string()))
        }
    }
}
